package com.tencent.wxcloudrun.service.business.fangdong;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tencent.wxcloudrun.config.CustomException;
import com.tencent.wxcloudrun.config.UserContext;
import com.tencent.wxcloudrun.dao.XCloudPointMapper;
import com.tencent.wxcloudrun.pojo.bo.HouseStatusEnum;
import com.tencent.wxcloudrun.pojo.bo.MediaInfo;
import com.tencent.wxcloudrun.pojo.bo.MediaOriInfo;
import com.tencent.wxcloudrun.pojo.bo.NoticeConstant;
import com.tencent.wxcloudrun.pojo.dto.req.AddHouseReq;
import com.tencent.wxcloudrun.pojo.dto.req.UpdateHouseReq;
import com.tencent.wxcloudrun.pojo.dto.resp.GetCityTagResp;
import com.tencent.wxcloudrun.pojo.dto.resp.GetFuYongResp;
import com.tencent.wxcloudrun.pojo.dto.resp.GetHomeListResp;
import com.tencent.wxcloudrun.pojo.dto.resp.UdIdToListResp;
import com.tencent.wxcloudrun.pojo.po.*;
import com.tencent.wxcloudrun.service.*;
import com.tencent.wxcloudrun.service.business.MapCloudService;
import com.tencent.wxcloudrun.service.business.NoticeService;
import com.tencent.wxcloudrun.service.business.map.MapService;
import com.tencent.wxcloudrun.util.DistanceUtils;
import com.tencent.wxcloudrun.util.IdUtil;
import com.tencent.wxcloudrun.util.WinXinUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 房屋管理
 */
@Slf4j
@Service
public class HouseManageService {

    private static final String REDIS_HOUSE_TAG = "redisHouseTag";

    private static final String REDIS_CITY_TAG = "redisCityTag";

    @Resource
    private DistanceUtils distanceUtils;

    @Resource
    private MapCloudService mapCloudService;

    @Resource
    private XCloudPointMapper xCloudPointMapper;

    @Resource
    private MapService mapService;

    @Resource
    private WinXinUtils winXinUtils;

    @Resource
    private XConstantService xConstantService;

    @Resource
    private XCloudTableService xCloudTableService;

    @Resource
    private XPersonInfoService xPersonInfoService;

    @Resource
    private XHelpmateInfoService xHelpmateInfoService;

    @Resource
    private XCloudPointService xCloudPointService;

    @Resource
    private XApplyLandService xApplyLandService;

    @Resource
    private XHouseInfoService xHouseInfoService;

    @Resource
    private XHouseTagService xHouseTagService;

    @Resource
    private XHouseQrcodeService xHouseQrcodeService;

    @Resource
    private XHouseAuthMiddleService xHouseAuthMiddleService;

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Resource
    private NoticeService noticeService;

    public static String getLastPartAfterDot(String input) {
        int lastDotIndex = input.lastIndexOf('.');
        if (lastDotIndex == -1) {
            return input;  // 如果没有找到 .
        }
        return input.substring(lastDotIndex + 1);
    }

    /**
     * 房屋标签的总枚举值
     */
    public List<String> getHouseTag() {
        String redisTag = redisTemplate.opsForValue().get(REDIS_HOUSE_TAG);
        if (StrUtil.isNotBlank(redisTag)) {
            return JSON.parseArray(redisTag, String.class);
        }
        LambdaQueryWrapper<XConstant> xConstantLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xConstantLambdaQueryWrapper.eq(XConstant::getType01, "house_tag");
        xConstantLambdaQueryWrapper.eq(XConstant::getOpenFlag, "open");
        List<XConstant> house_tag = xConstantService.list(xConstantLambdaQueryWrapper);
        // 使用【值2】进行升序排序
        List<XConstant> sortedList = house_tag.stream()
                .sorted(Comparator.comparingInt(x -> Integer.parseInt(x.getValue02())))
                .collect(Collectors.toList());
        // 只返回所需信息即可
        List<String> respList = new ArrayList<>();
        for (XConstant xConstant : sortedList) {
            respList.add(xConstant.getValue01());
        }
        redisTemplate.opsForValue().set(REDIS_HOUSE_TAG, JSON.toJSONString(respList), 2, TimeUnit.HOURS);
        log.info("tagList: " + JSON.toJSONString(respList));
        return respList;
    }

    /**
     * key：长沙  value：111222 <br>
     * ...
     */
    public JSONObject getCity() {
        String cityTag = redisTemplate.opsForValue().get(REDIS_CITY_TAG);
        if (StrUtil.isNotBlank(cityTag)) {
            return JSON.parseObject(cityTag);
        }
        List<XCloudTable> all = xCloudTableService.list();
        JSONObject jsonObject = new JSONObject();
        for (XCloudTable xCloudTable : all) {
            jsonObject.put(xCloudTable.getTableName(), xCloudTable.getTableId());
        }
        redisTemplate.opsForValue().set(REDIS_CITY_TAG, JSON.toJSONString(jsonObject), 2, TimeUnit.HOURS);
        return jsonObject;
    }

    /**
     * 新增房屋信息
     */
    @Transactional(rollbackFor = Exception.class)
    public String addHouse(AddHouseReq req) {
        log.info("addHomeReq--->  " + JSON.toJSONString(req));
        List<MediaOriInfo> collect = req.getMedia().stream().filter(var -> "jpeg".equalsIgnoreCase(var.getName().split("\\.")[1]) ||
                "jpg".equalsIgnoreCase(var.getName().split("\\.")[1]) ||
                "png".equalsIgnoreCase(var.getName().split("\\.")[1])).collect(Collectors.toList());
        if (CollUtil.isEmpty(collect)) {
            throw new CustomException("请至少上传一张图片！");
        }
        Date date = new Date();
        String openId = UserContext.getOpenId();
        log.info("检查当前用户是租客还是房东");
        LambdaQueryWrapper<XPersonInfo> xPersonInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xPersonInfoLambdaQueryWrapper.eq(XPersonInfo::getPersonId, openId);
        List<XPersonInfo> allByPersonId = xPersonInfoService.list(xPersonInfoLambdaQueryWrapper);
        List<String> personTypeList = allByPersonId.stream().map(XPersonInfo::getPersonType).collect(Collectors.toList());
        if (!personTypeList.contains("landlord") && !personTypeList.contains("helpmate")) { // 既不是房东也不是助理
            throw new CustomException("身份非法，不能进行新增房屋操作。");
        }
        String landId = openId; // 助理操作时，要获取到房东的OPENID
        if (!personTypeList.contains("landlord") && personTypeList.contains("helpmate")) { // 只是助理
            LambdaQueryWrapper<XHelpmateInfo> xHelpmateInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
            xHelpmateInfoLambdaQueryWrapper.eq(XHelpmateInfo::getHelpmateId, openId);
            landId = xHelpmateInfoService.getOne(xHelpmateInfoLambdaQueryWrapper).getLandlordId();
        }
        log.info("先确定该坐标点属于哪个市的。");
        JSONObject jsonObject = mapCloudService.geoCoder(req.getLatitude(), req.getLongitude());
        log.info("geoCoder resp  " + JSON.toJSONString(jsonObject));
        String cityFromJSON = mapCloudService.getCityFromJSON(jsonObject).replace("市", ""); // 城市名
        List<String> cityTagS = mapService.getCityTag().stream().map(GetCityTagResp::getCity).collect(Collectors.toList());
        if (!cityTagS.contains(cityFromJSON)) {
            throw new CustomException("当前不支持【" + cityFromJSON + "】市的房屋管理。");
        }
        /*
            云储存的实时数据与云搜索的数据都要进行查找，有一定概率无法将坐标点进行归档。
            比如地图云对一个点建立索引的时间是5分钟，在5分钟中内，有当前坐标点8米之外的位置被新建了超过200个，则此点不能被归档。
            此概率较低，业务上可对此问题容忍。
         */
        log.info("检查当前坐标是否8米内已有坐标点。");
        String udId = null; // 初始化当前房屋所属坐标组
        boolean newUdid = false; // 用于判断是否是新的坐标点
        boolean oneFlag = true; // 用于判断是否需要经行云搜索判断
        BigDecimal firstPrice = null;
        String tableId = getCity().getString(cityFromJSON); //所在城市对应的表ID
        JSONObject dataList = mapCloudService.dataList(tableId);
        log.info("dataList resp  " + JSON.toJSONString(dataList));
        List<JSONObject> pointFromJSON = mapCloudService.getPointFromJSON(dataList);
        for (JSONObject stringObjectMap : pointFromJSON) {
            double distance = distanceUtils.calculateDistance(req.getLatitude(), req.getLongitude(), stringObjectMap.getDouble("lat"), stringObjectMap.getDouble("lng"));
            if (distance <= 8) {
                udId = stringObjectMap.getString("udId");
                oneFlag = false;
                firstPrice = stringObjectMap.getBigDecimal("price");
                break;
            }
        }
        if (oneFlag) { // 在云存储中没有找到8米以内的坐标点，开始尝试用云搜索进行查找
            JSONObject searchNearby = mapCloudService.searchNearby(tableId, req.getLatitude() + "," + req.getLongitude(), "8", null, null);
            log.info("searchNearby resp  " + JSON.toJSONString(searchNearby));
            List<JSONObject> cloudSearchList = mapCloudService.getPointFromJSON(searchNearby);
            if (CollUtil.isNotEmpty(cloudSearchList)) { // 云存储中有找到8米以内的点
                udId = cloudSearchList.get(0).getString("udId");
                firstPrice = cloudSearchList.get(0).getBigDecimal("price");
            }
        }
        if (StrUtil.isBlank(udId)) { // 云存储与云搜索 都没有找到8米以内的点，则让该点成为此范围的第一个点。
            XCloudPoint xCloudPoint = xCloudPointMapper.getMaxIdRecord();
            if (ObjUtil.isNull(xCloudPoint) || StrUtil.isBlank(xCloudPoint.getUdId())) {
                udId = String.valueOf(1);
            } else {
                udId = String.valueOf(xCloudPoint.getId() + 1);
            }
            newUdid = true;
        }
        // 如果是该点为新增的，则add x_cloud_point表，并且调用data/create接口在【腾讯位置服务中进行点的新增】
        if (newUdid) {
            XCloudPoint xCloudPoint = new XCloudPoint();
            xCloudPoint.setUdId(udId);
            String address = jsonObject.getString("address"); // 这个必有  以行政区划+道路+门牌号等信息组成的标准格式化地址
            JSONObject formattedAddresses = jsonObject.getJSONObject("formatted_addresses"); // 结合知名地点形成的描述性地址，更具人性化特点
            String recommend = formattedAddresses.getString("recommend"); // 可能没有  推荐使用的地址描述，描述精确性较高
            String rough = formattedAddresses.getString("rough"); // 可能没有  粗略位置描述
            String standardAddress = formattedAddresses.getString("standard_address"); // 可能没有  基于附近关键地点（POI）的精确地址
            String title = address; // 最低优先级的title
            if (StrUtil.isNotBlank(rough)) {
                title = rough; // 第三优先
            }
            if (StrUtil.isNotBlank(recommend)) {
                title = recommend; // 第二优先这个名称
            }
            if (StrUtil.isNotBlank(standardAddress)) {
                title = standardAddress; // 最优先这个名字
            }
            // 向地图云中添加点信息
            JSONObject dataCre = new JSONObject();
            dataCre.put("ud_id", udId);
            dataCre.put("title", title);
            dataCre.put("lat", req.getLatitude());
            dataCre.put("lng", req.getLongitude());
            dataCre.put("table_id", tableId);
            dataCre.put("price", req.getMouthMoney());
            mapCloudService.dataCreate(dataCre);
            xCloudPoint.setTitle(title);
            xCloudPoint.setAddress(req.getAddress());
            xCloudPoint.setLat(req.getLatitude());
            xCloudPoint.setLng(req.getLongitude());
            xCloudPoint.setPrice(req.getMouthMoney());
            xCloudPoint.setCreateTime(date);
            xCloudPoint.setUpdateTime(date);
            xCloudPointService.save(xCloudPoint);
        } else { // 该点已经存在过，检查价格是否需要更新
            if (ObjUtil.isNotNull(firstPrice) && req.getMouthMoney().compareTo(firstPrice) < 0) {
                JSONObject dataCre = new JSONObject();
                dataCre.put("ud_id", udId);
                dataCre.put("table_id", tableId);
                dataCre.put("price", req.getMouthMoney());
                mapCloudService.dataUpdate(dataCre);
            }
        }
        String houseId = IdUtil.generateHouseId();
        XHouseInfo houseInfo = new XHouseInfo(); // 最后存表的对象
        houseInfo.setHouseId(houseId);
        // 对图片视频信息进行一个加工，确保首个元素是图片
        List<MediaOriInfo> media = req.getMedia();
        List<MediaOriInfo> picList = new ArrayList<>();
        List<MediaOriInfo> mediaList = new ArrayList<>();
        List<MediaOriInfo> lastList = new ArrayList<>();
        for (MediaOriInfo mediaOriInfo : media) {
            String fileID = mediaOriInfo.getFileID();
            if (fileID.endsWith("JPEG") || fileID.endsWith("jpeg") || fileID.endsWith("jpg") || fileID.endsWith("JPG") ||
                    fileID.endsWith("PNG") || fileID.endsWith("png")) {
                picList.add(mediaOriInfo);
            } else {
                mediaList.add(mediaOriInfo);
            }
        }
        if (CollUtil.isNotEmpty(picList)) {
            lastList.addAll(picList);
        }
        if (CollUtil.isNotEmpty(mediaList)) {
            lastList.addAll(mediaList);
        }
        req.setMedia(lastList);

        houseInfo.setPicId(MediaInfo.transMediaListToStr(req.getMedia()));
        houseInfo.setHouseName(req.getHouseName());
        houseInfo.setAddress(req.getAddress());
        houseInfo.setPointId(udId);
        houseInfo.setFloor(req.getFloor());
        houseInfo.setArea(req.getArea());
        houseInfo.setLandlordId(landId);
        houseInfo.setHouseState(HouseStatusEnum.WAIT_RENT.getValue());
        houseInfo.setRefreshTime(date);
        houseInfo.setPicAuth("no");
        houseInfo.setWaterPrice(req.getWaterPrice());
        houseInfo.setLastWaterValue(req.getLastWaterValue());
        houseInfo.setPowerPrice(req.getPowerPrice());
        houseInfo.setLastPowerValue(req.getLastPowerValue());
        houseInfo.setGasPrice(req.getGasPrice());
        houseInfo.setLastGasValue(req.getLastGasValue());
        houseInfo.setMouthMoney(req.getMouthMoney());
        houseInfo.setDeposit(req.getDeposit());
        houseInfo.setManageFee(req.getManageFee());
        houseInfo.setHouseRemark(req.getHouseRemark());
        houseInfo.setFeeRemark(req.getFeeRemark());
        houseInfo.setCreateId(openId);
        houseInfo.setCreateTime(date);
        houseInfo.setUpdateId(openId);
        houseInfo.setUpdateTime(date);
        xHouseInfoService.save(houseInfo);
        // 存标签
        List<XHouseTag> tagList = new ArrayList<>();
        for (String tag : req.getTag()) {
            XHouseTag XHouseTag = new XHouseTag();
            XHouseTag.setHouseId(houseId);
            XHouseTag.setTagId(tag);
            XHouseTag.setCreateTime(date);
            XHouseTag.setCreateId(openId);
            tagList.add(XHouseTag);
        }
        xHouseTagService.saveBatch(tagList);
        return "新增房屋成功！";
    }

    public List<GetHomeListResp> getHomeList() {
        String openId = UserContext.getOpenId();
        List<GetHomeListResp> respList = new ArrayList<>();
        List<XHouseInfo> all;
        all = getxHouseInfos(openId);
        for (XHouseInfo xHouseInfo : all) {
            GetHomeListResp getHomeListResp = new GetHomeListResp();
            if ("yes".equals(xHouseInfo.getPicAuth())) {
                getHomeListResp.setHouseName(xHouseInfo.getHouseName() + "（已认证）");
            }
            if ("ing".equals(xHouseInfo.getPicAuth())) {
                getHomeListResp.setHouseName(xHouseInfo.getHouseName() + "（认证中）");
            }
            if (StrUtil.isBlank(xHouseInfo.getPicAuth()) || "no".equals(xHouseInfo.getPicAuth())) {
                getHomeListResp.setHouseName(xHouseInfo.getHouseName() + "（未认证）");
            }
            getHomeListResp.setAddress(xHouseInfo.getAddress());
            getHomeListResp.setStatus(HouseStatusEnum.findByValue(xHouseInfo.getHouseState()).getKey());
            getHomeListResp.setHouseId(xHouseInfo.getHouseId());
            if (xHouseInfo.getPicId() != null) {
                List<MediaInfo> mediaInfoList = JSON.parseArray(xHouseInfo.getPicId(), MediaInfo.class);
                List<MediaInfo> collect = mediaInfoList.stream()
                        .filter(var -> "jpeg".equalsIgnoreCase(getLastPartAfterDot(var.getFileID())) ||
                                "jpg".equalsIgnoreCase(getLastPartAfterDot(var.getFileID())) ||
                                "png".equalsIgnoreCase(getLastPartAfterDot(var.getFileID()))).collect(Collectors.toList());
                if (CollUtil.isNotEmpty(collect)) {
                    getHomeListResp.setPic(collect.get(0).getFileID());
                }
            }
            respList.add(getHomeListResp);
        }
        return respList;
    }

    private List<XHouseInfo> getxHouseInfos(String openId) {
        List<XHouseInfo> all;
        // 检查当前人员是助理还是房东
        LambdaQueryWrapper<XHelpmateInfo> xHelpmateInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHelpmateInfoLambdaQueryWrapper.eq(XHelpmateInfo::getHelpmateId, openId);
        XHelpmateInfo xHelpmateInfoServiceOne = xHelpmateInfoService.getOne(xHelpmateInfoLambdaQueryWrapper);
        if (ObjectUtil.isNotNull(xHelpmateInfoServiceOne) && StrUtil.isNotBlank(xHelpmateInfoServiceOne.getLandlordId())) {
            // 表明当前用户是助理
            List<String> stringList = JSON.parseArray(xHelpmateInfoServiceOne.getHouseList(), String.class);
            if (CollUtil.isEmpty(stringList)) {
                throw new CustomException("当前助理尚无房屋信息！");
            }
            LambdaQueryWrapper<XHouseInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.in(XHouseInfo::getHouseId, stringList);
            all = xHouseInfoService.list(queryWrapper);
        } else {
            // 当前用户是房东的情况
            LambdaQueryWrapper<XHouseInfo> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(XHouseInfo::getLandlordId, openId);
            all = xHouseInfoService.list(queryWrapper);
        }
        return all;
    }

    /**
     * 检查房屋认证状态
     */
    public String checkHouseAuth(List<String> ids) {
        LambdaQueryWrapper<XHouseInfo> xHouseInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHouseInfoLambdaQueryWrapper.in(XHouseInfo::getHouseId, ids);
        List<XHouseInfo> list = xHouseInfoService.list(xHouseInfoLambdaQueryWrapper);
        List<String> collect = list.stream().map(XHouseInfo::getPicAuth).collect(Collectors.toList());
        if (CollUtil.isEmpty(collect) || collect.contains("no") || collect.contains("ing")) {
            throw new CustomException("不可勾选未认证或认证中的房屋");
        }
        return "所有房屋已认证，可以生成二维码";
    }

    @Transactional(rollbackFor = Exception.class)
    public byte[] getQrCodeId(String openId, List<String> ids, HttpServletResponse response) throws IOException {
        log.info(">>>>>> getQrCodeId的openId当前是：" + openId);
        String id = cn.hutool.core.util.IdUtil.getSnowflakeNextIdStr();
        String accessToken = winXinUtils.getAccessToken();
        HashMap<String, Object> bodyMap = new HashMap<>();
        bodyMap.put("page", "pages/zuke/qrcode/qrCode");
        bodyMap.put("check_path", false);
        bodyMap.put("env_version", "develop");
        bodyMap.put("scene", "a=" + id);
        byte[] buffer = HttpUtil.createPost("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + accessToken)
                .body(JSON.toJSONString(bodyMap)).execute().bodyBytes();
        // 将 Buffer 写入响应流
        OutputStream outputStream = response.getOutputStream();
        outputStream.write(buffer);
        outputStream.flush();
        outputStream.close();
        XHouseQrcode xHouseQrcode = new XHouseQrcode();
        xHouseQrcode.setBusinessId(id);
        xHouseQrcode.setHouseList(JSON.toJSONString(ids));
        xHouseQrcode.setCreateTime(new Date());
        xHouseQrcode.setCreatePerson(openId);
        xHouseQrcodeService.save(xHouseQrcode);
        return buffer;
    }

    public List<UdIdToListResp> getHomeInfoById(String id) {
        LambdaQueryWrapper<XHouseQrcode> xHouseQrcodeLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHouseQrcodeLambdaQueryWrapper.eq(XHouseQrcode::getBusinessId, id);
        XHouseQrcode one = xHouseQrcodeService.getOne(xHouseQrcodeLambdaQueryWrapper);
        List<String> stringList = JSON.parseArray(one.getHouseList(), String.class);
        LambdaQueryWrapper<XHouseInfo> xHouseInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHouseInfoLambdaQueryWrapper.in(XHouseInfo::getHouseId, stringList);
        xHouseInfoLambdaQueryWrapper.eq(XHouseInfo::getPicAuth, "yes");
        List<XHouseInfo> list = xHouseInfoService.list(xHouseInfoLambdaQueryWrapper);
        List<UdIdToListResp> respList = new ArrayList<>();
        for (XHouseInfo xHouseInfo : list) {
            UdIdToListResp udIdToListResp = new UdIdToListResp();
            String houseName = xHouseInfo.getHouseName() != null ? xHouseInfo.getHouseName() : "未知房名";
            String floor = xHouseInfo.getFloor() != null ? xHouseInfo.getFloor() + "楼" : "未知楼层";
            String mouthMoney = (xHouseInfo.getMouthMoney() != null) ? xHouseInfo.getMouthMoney().toPlainString() + "元" : "价格未知";
            udIdToListResp.setHouseInfo(houseName + "_" + floor + "_" + mouthMoney);
            // 获取标签（注意：之前写的是 openId，其实应该是 houseId）
            LambdaQueryWrapper<XHouseTag> xHouseTagLambdaQueryWrapper = new LambdaQueryWrapper<>();
            xHouseTagLambdaQueryWrapper.eq(XHouseTag::getHouseId, xHouseInfo.getHouseId());
            List<XHouseTag> allByHouseId = xHouseTagService.list(xHouseTagLambdaQueryWrapper);
            if (allByHouseId != null) {
                List<String> tagList = allByHouseId.stream()
                        .map(XHouseTag::getTagId)
                        .filter(Objects::nonNull)
                        .limit(4)
                        .collect(Collectors.toList());
                udIdToListResp.setTagList(StrUtil.join("、", tagList));
            }
            // 房屋状态
            if (xHouseInfo.getHouseState() != null) {
                HouseStatusEnum statusEnum = HouseStatusEnum.findByValue(xHouseInfo.getHouseState());
                if (statusEnum != null) {
                    udIdToListResp.setHouseStatus(statusEnum.getKey());
                } else {
                    log.warn("Unknown house state: {}", xHouseInfo.getHouseState());
                }
            }
            // 图片处理
            if (xHouseInfo.getPicId() != null) {
                try {
                    List<MediaInfo> mediaInfoList = JSON.parseArray(xHouseInfo.getPicId(), MediaInfo.class);
                    if (mediaInfoList != null) {
                        List<MediaInfo> picCol = mediaInfoList.stream()
                                .filter(var -> {
                                    String suffix = HouseManageService.getLastPartAfterDot(var.getFileID());
                                    return "jpeg".equalsIgnoreCase(suffix) ||
                                            "jpg".equalsIgnoreCase(suffix) ||
                                            "png".equalsIgnoreCase(suffix);
                                })
                                .collect(Collectors.toList());

                        if (!picCol.isEmpty()) {
                            udIdToListResp.setPic(picCol.get(0).getFileID());
                        }
                    }
                } catch (Exception e) {
                    log.error("Error parsing picId JSON for houseId: {}", xHouseInfo.getHouseId(), e);
                }
            }
            // 设置索引（houseId）
            udIdToListResp.setIndex(xHouseInfo.getHouseId());
            respList.add(udIdToListResp);
        }
        return respList;
    }

    @Transactional
    public String updateHouseStatus(String houseId, String status) {
        LambdaQueryWrapper<XHouseInfo> xHouseInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHouseInfoLambdaQueryWrapper.eq(XHouseInfo::getHouseId, houseId);
        XHouseInfo houseInfo = new XHouseInfo();
        houseInfo.setHouseState(HouseStatusEnum.findByKey(status).getValue());
        xHouseInfoService.update(houseInfo, xHouseInfoLambdaQueryWrapper);
        return "更新成功！";
    }

    public GetFuYongResp getFuYong() {
        String openId = UserContext.getOpenId();
        List<XHouseInfo> xHouseInfos = getxHouseInfos(openId);
        if (CollUtil.isEmpty(xHouseInfos)) {
            throw new CustomException("当前用户没有房屋信息！");
        }
        Set<String> seenPointIds = new HashSet<>(); // 用于跟踪已出现的pointId
        List<XHouseInfo> distinctList = xHouseInfos.stream().filter(house -> seenPointIds.add(house.getPointId())).collect(Collectors.toList()); // 去重
        List<GetFuYongResp.Address> respList = new ArrayList<>();
        // 对 xHouseInfos参数使用其中的 address字段进行去重，用stream表达式
        for (XHouseInfo xHouseInfo : distinctList) {
            GetFuYongResp.Address getFuYongResp = new GetFuYongResp.Address();
            getFuYongResp.setAddress(xHouseInfo.getAddress());
            LambdaQueryWrapper<XCloudPoint> xCloudPointLambdaQueryWrapper = new LambdaQueryWrapper<>();
            xCloudPointLambdaQueryWrapper.eq(XCloudPoint::getUdId, xHouseInfo.getPointId());
            XCloudPoint pointServiceOne = xCloudPointService.getOne(xCloudPointLambdaQueryWrapper);
            getFuYongResp.setLatitude(pointServiceOne.getLat());
            getFuYongResp.setLongitude(pointServiceOne.getLng());
            respList.add(getFuYongResp);
        }
        List<String> houseCollect = xHouseInfos.stream().map(XHouseInfo::getHouseRemark).distinct().collect(Collectors.toList());
        List<String> feeCollect = xHouseInfos.stream().map(XHouseInfo::getFeeRemark).distinct().collect(Collectors.toList());
        GetFuYongResp getFuYongResp = new GetFuYongResp();
        getFuYongResp.setAddressList(respList);
        getFuYongResp.setHouseRemark(houseCollect);
        getFuYongResp.setFeeRemark(feeCollect);
        return getFuYongResp;
    }

    public String checkHouseAuthIng(List<String> ids) {
        LambdaQueryWrapper<XHouseInfo> xHouseInfoLambdaQueryWrapper1 = new LambdaQueryWrapper<>();
        xHouseInfoLambdaQueryWrapper1.in(XHouseInfo::getHouseId, ids);
        List<XHouseInfo> list = xHouseInfoService.list(xHouseInfoLambdaQueryWrapper1);
        List<String> collect = list.stream().map(XHouseInfo::getPicAuth).distinct().collect(Collectors.toList());
        if (collect.contains("ing") || collect.contains("yes")) {
            throw new CustomException("只能勾选未认证的房屋");
        }
        return "ok";
    }

    @Transactional
    public String applyHouseAuth(List<String> ids) {
        String openId = UserContext.getOpenId();
        XHouseAuthMiddle xHouseAuthMiddle = new XHouseAuthMiddle();
        LambdaQueryWrapper<XHelpmateInfo> xHelpmateInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHelpmateInfoLambdaQueryWrapper.eq(XHelpmateInfo::getHelpmateId, openId);
        XHelpmateInfo xHelpmateInfoServiceOne = xHelpmateInfoService.getOne(xHelpmateInfoLambdaQueryWrapper);
        if (ObjectUtil.isNull(xHelpmateInfoServiceOne)) { // 说明当前用户就是房东
            xHouseAuthMiddle.setLandId(openId);
            LambdaQueryWrapper<XPersonInfo> xPersonInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
            xPersonInfoLambdaQueryWrapper.eq(XPersonInfo::getPersonId, openId).eq(XPersonInfo::getPersonType, "landlord");
            XPersonInfo xPersonInfoServiceOne = xPersonInfoService.getOne(xPersonInfoLambdaQueryWrapper);
            xHouseAuthMiddle.setLandName(xPersonInfoServiceOne.getCardName());
            xHouseAuthMiddle.setApplyPhone(xPersonInfoServiceOne.getPhone());
            xHouseAuthMiddle.setApplyPersonType("land");
        } else {
            xHouseAuthMiddle.setLandId(xHelpmateInfoServiceOne.getLandlordId());
            xHouseAuthMiddle.setApplyPhone(xHelpmateInfoServiceOne.getHelpPhone());
            LambdaQueryWrapper<XPersonInfo> xPersonInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
            xPersonInfoLambdaQueryWrapper.eq(XPersonInfo::getPersonId, xHelpmateInfoServiceOne.getLandlordId()).eq(XPersonInfo::getPersonType, "landlord");
            XPersonInfo xPersonInfoServiceOne = xPersonInfoService.getOne(xPersonInfoLambdaQueryWrapper);
            xHouseAuthMiddle.setLandName(xPersonInfoServiceOne.getCardName());
            xHouseAuthMiddle.setApplyPersonType("helpmate");
        }
        xHouseAuthMiddle.setAuthId(cn.hutool.core.util.IdUtil.getSnowflakeNextIdStr());
        xHouseAuthMiddle.setHouseList(JSON.toJSONString(ids));
        xHouseAuthMiddle.setCreateId(openId);
        xHouseAuthMiddle.setCreateTime(new Date());
        xHouseAuthMiddleService.save(xHouseAuthMiddle);
        LambdaQueryWrapper<XHouseInfo> xHouseInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHouseInfoLambdaQueryWrapper.in(XHouseInfo::getHouseId, ids);
        XHouseInfo houseInfo = new XHouseInfo();
        houseInfo.setPicAuth("ing");
        xHouseInfoService.update(houseInfo, xHouseInfoLambdaQueryWrapper);

        if (ObjectUtil.isNull(xHelpmateInfoServiceOne)) {
            // 当前用户是房东
            noticeService.createNotice("land", NoticeConstant.HOUSE_AUTH_APPLY_TITLE,
                    String.format(NoticeConstant.HOUSE_AUTH_APPLY_CONTENT, ids.size(), ""));
        } else {
            // 当前用户是助理
            // 给助理发送通知
            noticeService.createNotice("helpmate", NoticeConstant.HOUSE_AUTH_APPLY_TITLE,
                    String.format(NoticeConstant.HOUSE_AUTH_APPLY_CONTENT, ids.size(), ""));

            // 给房东发送通知
            noticeService.createNoticeByOpenid(xHelpmateInfoServiceOne.getLandlordId(), "land",
                    NoticeConstant.HOUSE_AUTH_APPLY_TITLE,
                    String.format(NoticeConstant.HOUSE_AUTH_APPLY_CONTENT, ids.size(), "该申请由" + xHelpmateInfoServiceOne.getAlias() + "发起。"));
        }

        return "申请成功！";
    }

    @Transactional
    public String updateHouse(UpdateHouseReq req) {
        String openId = UserContext.getOpenId();
        Date date = new Date();
        // 获取房屋现有的情况
        LambdaQueryWrapper<XHouseInfo> xHouseInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHouseInfoLambdaQueryWrapper.eq(XHouseInfo::getHouseId, req.getHouseId());
        XHouseInfo houseInfo = xHouseInfoService.getOne(xHouseInfoLambdaQueryWrapper);
        XHouseInfo xHouseInfo = new XHouseInfo();
        xHouseInfo.setId(houseInfo.getId());
        xHouseInfo.setHouseId(req.getHouseId());
        // 对图片视频信息进行一个加工，确保首个元素是图片
        List<MediaInfo> media = req.getPicId();
        List<MediaInfo> picList = new ArrayList<>();
        List<MediaInfo> mediaList = new ArrayList<>();
        List<MediaInfo> lastList = new ArrayList<>();
        for (MediaInfo mediaOriInfo : media) {
            String fileID = mediaOriInfo.getFileID();
            if (fileID.endsWith("JPEG") || fileID.endsWith("jpeg") || fileID.endsWith("jpg") || fileID.endsWith("JPG") ||
                    fileID.endsWith("PNG") || fileID.endsWith("png")) {
                picList.add(mediaOriInfo);
            } else {
                mediaList.add(mediaOriInfo);
            }
        }
        if (CollUtil.isNotEmpty(picList)) {
            lastList.addAll(picList);
        }
        if (CollUtil.isNotEmpty(mediaList)) {
            lastList.addAll(mediaList);
        }
        req.setPicId(lastList);

        if (CollUtil.isNotEmpty(req.getPicId())) xHouseInfo.setPicId(JSONObject.toJSONString(req.getPicId()));
        if (StrUtil.isNotBlank(req.getHouseName())) xHouseInfo.setHouseName(req.getHouseName());
        if (StrUtil.isNotBlank(req.getAddress())) xHouseInfo.setAddress(req.getAddress());
        if (StrUtil.isNotBlank(req.getFloor())) xHouseInfo.setFloor(req.getFloor());
        if (StrUtil.isNotBlank(req.getArea())) xHouseInfo.setArea(req.getArea());
        xHouseInfo.setRefreshTime(date);
        if (ObjectUtil.isNotNull(req.getWaterPrice())) xHouseInfo.setWaterPrice(req.getWaterPrice());
        if (ObjectUtil.isNotNull(req.getPowerPrice())) xHouseInfo.setPowerPrice(req.getPowerPrice());
        if (ObjectUtil.isNotNull(req.getGasPrice())) xHouseInfo.setGasPrice(req.getGasPrice());
        if (ObjectUtil.isNotNull(req.getMouthMoney())) xHouseInfo.setMouthMoney(req.getMouthMoney());
        if (ObjectUtil.isNotNull(req.getDeposit())) xHouseInfo.setDeposit(req.getDeposit());
        if (ObjectUtil.isNotNull(req.getManageFee())) xHouseInfo.setManageFee(req.getManageFee());
        if (StrUtil.isNotBlank(req.getHouseRemark())) xHouseInfo.setHouseRemark(req.getHouseRemark());
        if (StrUtil.isNotBlank(req.getFeeRemark())) xHouseInfo.setFeeRemark(req.getFeeRemark());
        if (StrUtil.isNotBlank(req.getLastWaterValue())) xHouseInfo.setLastWaterValue(req.getLastWaterValue());
        if (StrUtil.isNotBlank(req.getLastPowerValue())) xHouseInfo.setLastPowerValue(req.getLastPowerValue());
        if (StrUtil.isNotBlank(req.getLastGasValue())) xHouseInfo.setLastGasValue(req.getLastGasValue());
        xHouseInfo.setUpdateId(openId);
        xHouseInfo.setUpdateTime(date);
        xHouseInfoService.updateById(xHouseInfo);
        // 标签变更
        if (CollUtil.isNotEmpty(req.getTagList())) {
            LambdaQueryWrapper<XHouseTag> xHouseTagLambdaQueryWrapper = new LambdaQueryWrapper<>();
            xHouseTagLambdaQueryWrapper.eq(XHouseTag::getHouseId, req.getHouseId());
            xHouseTagService.remove(xHouseTagLambdaQueryWrapper);
            List<XHouseTag> xHouseTagList = new ArrayList<>();
            List<String> tagList = req.getTagList();
            for (String ss : tagList) {
                XHouseTag xHouseTag = new XHouseTag();
                xHouseTag.setHouseId(req.getHouseId());
                xHouseTag.setTagId(ss);
                xHouseTag.setCreateTime(date);
                xHouseTag.setCreateId(openId);
                xHouseTagList.add(xHouseTag);
            }
            xHouseTagService.saveBatch(xHouseTagList);
        }
        // 修改x_cloud_point表
        if (StrUtil.isNotBlank(req.getAddress()) || ObjectUtil.isNotNull(req.getMouthMoney())) {
            String pointId = houseInfo.getPointId();
            LambdaQueryWrapper<XCloudPoint> xCloudPointLambdaQueryWrapper = new LambdaQueryWrapper<>();
            xCloudPointLambdaQueryWrapper.eq(XCloudPoint::getUdId, pointId);
            XCloudPoint xCloudPoint = new XCloudPoint();
            xCloudPoint.setUdId(pointId);
            xCloudPoint.setAddress(req.getAddress());
            xCloudPoint.setPrice(req.getMouthMoney());
            xCloudPoint.setUpdateTime(date);
            xCloudPointService.update(xCloudPoint, xCloudPointLambdaQueryWrapper);
        }
        if (!Objects.equals(houseInfo.getMouthMoney(), req.getMouthMoney())) { // 月租金发生修改要通知至地图云
            LambdaQueryWrapper<XCloudPoint> xCloudPointLambdaQueryWrapper = new LambdaQueryWrapper<>();
            xCloudPointLambdaQueryWrapper.eq(XCloudPoint::getUdId, houseInfo.getPointId());
            XCloudPoint pointServiceOne = xCloudPointService.getOne(xCloudPointLambdaQueryWrapper);
            JSONObject jsonObject = mapCloudService.geoCoder(pointServiceOne.getLat(), pointServiceOne.getLng());
            log.info("geoCoder resp  " + JSON.toJSONString(jsonObject));
            String cityFromJSON = mapCloudService.getCityFromJSON(jsonObject).replace("市", ""); // 城市名
            LambdaQueryWrapper<XCloudTable> xCloudTableLambdaQueryWrapper = new LambdaQueryWrapper<>();
            xCloudTableLambdaQueryWrapper.eq(XCloudTable::getTableName, cityFromJSON);
            XCloudTable xCloudTable = xCloudTableService.getOne(xCloudTableLambdaQueryWrapper);
            JSONObject jsonObject1 = new JSONObject();
            jsonObject1.put("ud_id", pointServiceOne.getUdId());
            jsonObject1.put("table_id", xCloudTable.getTableId());
            jsonObject1.put("price", req.getMouthMoney());
            mapCloudService.dataUpdate(jsonObject1);
        }
        return "success";
    }

    @Transactional
    public String logOff() {
        String openId = UserContext.getOpenId();
        Date date = new Date();
        // 检查当前名下是否有房子正处于出租状态
        LambdaQueryWrapper<XHouseInfo> xHouseInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHouseInfoLambdaQueryWrapper.eq(XHouseInfo::getLandlordId, openId);
        List<XHouseInfo> houseInfoList = xHouseInfoService.list(xHouseInfoLambdaQueryWrapper);
        // 没有租客ID的房屋就是没有出租的
        List<XHouseInfo> xHouseInfos = houseInfoList.stream().filter(var -> StrUtil.isBlank(var.getTenantId())).collect(Collectors.toList());
        if (houseInfoList.size() != xHouseInfos.size()) {
            throw new CustomException("有房子处于出租状态，不能注销");
        }
        // 移除该房东手底下助理的x_person_info表信息
        LambdaQueryWrapper<XHelpmateInfo> helpInfoWrapper = new LambdaQueryWrapper<>();
        helpInfoWrapper.eq(XHelpmateInfo::getLandlordId, openId);
        List<XHelpmateInfo> xHelpmateInfos = xHelpmateInfoService.list(helpInfoWrapper);
        if (CollUtil.isNotEmpty(xHelpmateInfos)) {
            for (XHelpmateInfo helpmateInfo : xHelpmateInfos) {
                LambdaQueryWrapper<XPersonInfo> xPersonInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
                xPersonInfoLambdaQueryWrapper.eq(XPersonInfo::getPersonId, helpmateInfo.getHelpmateId());
                xPersonInfoLambdaQueryWrapper.eq(XPersonInfo::getPersonType, "helpmate");
                xPersonInfoService.remove(xPersonInfoLambdaQueryWrapper);
            }
        }
        // 更新房屋状态为 已过期
        XHouseInfo xHouseInfo = new XHouseInfo();
        xHouseInfo.setHouseState(HouseStatusEnum.EXPIRE.getValue());
        xHouseInfo.setUpdateTime(date);
        xHouseInfoService.update(xHouseInfo, xHouseInfoLambdaQueryWrapper);
        // 删除x_apply_land  x_helpmate_info  x_person_info
        LambdaQueryWrapper<XApplyLand> xApplyLandLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xApplyLandLambdaQueryWrapper.eq(XApplyLand::getOpenId, openId);
        xApplyLandService.remove(xApplyLandLambdaQueryWrapper);
        LambdaQueryWrapper<XHelpmateInfo> xHelpmateInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHelpmateInfoLambdaQueryWrapper.eq(XHelpmateInfo::getLandlordId, openId);
        xHelpmateInfoService.remove(xHelpmateInfoLambdaQueryWrapper);
        LambdaQueryWrapper<XPersonInfo> xPersonInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xPersonInfoLambdaQueryWrapper.eq(XPersonInfo::getPersonId, openId);
        xPersonInfoLambdaQueryWrapper.eq(XPersonInfo::getPersonType, "landlord");
        xPersonInfoService.remove(xPersonInfoLambdaQueryWrapper);
        return "注销成功！";
    }
}
